/**
 * luffy.common.TemplateLoader
 * 페이지에 관련 엘리먼트가 없을 경우, 필요한 엘리먼트를 생성하기 위해 서버로부터 마크업 템플릿을 로딩하는 플러그인.
 * LOAD_TEMPLATE 메시지에 입력받은 id에 해당하는 템플릿을 가지고 있으면, 이 템플릿을 반환하고, (데이터까지 받았을때는 바인딩하여 반환)
 * 템플릿을 가지고 있지 않으면 서버에 요청하여 템플릿을 받아 파싱 후 템플릿을 반환. 이 경우에는 비동기로 동작하게 되므로, 
 * http://wiki.nhncorp.com/display/lsuit/luffy.common.TemplateLoader 에 명세된 패턴으로 클래스를 작성하는 것을 권장함.
 * 
 * TODO : 템플릿 로딩 시, 관련된 CSS도 같이 로딩할 수 있는 기능을 추가해야 함. 
 *        TemplateID와 CSS 로딩 간의 규칙도 수립해야 함. (id만으로 template /css 모두 로딩 가능하도록)
 * 
 * @author Gloridea
 * @see http://wiki.nhncorp.com/display/lsuit/luffy.common.TemplateLoader
 */
luffy.common.TemplateLoader = jindo.$Class({
	
	name : 'TemplateLoader',
	
	_htTemplateUrl: "",
	
	_htCache: null,
	_aCallbackQueue: null,
	_htRequestedUrl: null,
	
	_nRemainedReq : 0,
	
	$init: function(oOptions) {
		this._htCache = {};
		this._aCallbackQueue = [];
		this._htRequestedUrl = {};
		
		if (oOptions) {
			if (oOptions.templateUrl) {
				this._htTemplateUrl = oOptions.templateUrl;
			}
			
			this._initTemplateUrlList();
		}
		
		this._htCache = luffy.common.TemplateHTML;
//		this._preRequestTemplate(oOptions.templateUrl);
	},

	/**
	 * TemplateURL 매칭 규칙을 생성함
	 * TemplateURL은 wiki에 명세된대로, 3가지 데이터 타입 (String, Function, Regexp)을 받을 수 있으므로,
	 * Function으로 받지 않은 것은 모두 Function으로 만들어줘야 함.
	 * 만들어진 Function이 true를 반환하면 해당 key를 요청 URL로 사용해도 됨을 의미함.(wiki참조)
	 */
	_initTemplateUrlList: function() {
		if (typeof this._htTemplateUrl == "string") {
			var sUrl = this._htTemplateUrl;
			this._htTemplateUrl = {};
			this._htTemplateUrl[sUrl] = function() { return true; };
			return;
		}
		
		for (var sEachUrl in this._htTemplateUrl) {
			var oEachCondition = this._htTemplateUrl[sEachUrl];
			
			if (oEachCondition instanceof RegExp) {
				this._htTemplateUrl[sEachUrl] = (function(rxCondition){ 
					return function(sTemplateId) {
						return rxCondition.test(sTemplateId);
					};
				}(oEachCondition));
			}
		}
	},
	
	// 속성에 대한 정의는 BEFORE_에 정의한다.
	$BEFORE_MSG_APP_READY : function(){
		this.oApp.exec("ADD_APP_PROPERTY", ["getTemplate", jindo.$Fn(this._getTemplate, this).bind()]);
	},
	
	_getTemplate : function(sTplId){
		return this._htCache[sTplId];
	},
	
	$ON_LOAD_TEMPLATE: function(oRequest, fCallback) {
		if (typeof oRequest == "string") {
			oRequest = { id: oRequest };
		}

//		var aUnloadedIdList = this._getUnloadedIdList(oRequest);
//		
//		if (aUnloadedIdList.length > 0) {
//			this._aCallbackQueue.push({
//				idList: aUnloadedIdList,
//				request: oRequest,
//				callback: fCallback
//			});
//			
//			this._requestUnloaded(aUnloadedIdList);
//			return;
//		} else {
			this._runSingleCallback(oRequest, fCallback);
//		}
	},

	/**
	 * 템플릿 URL을 요청한다.
	 * URL로부터 받아진 템플릿은 파싱하고, 큐에 쌓인 URL에 템플릿을 반환해준다. 
	 */
	_requestTemplate: function(sUrl) {
		var oSelf = this;
		this._nRemainedReq++;
		
		(new luffy.common.Util.XHR()).attach({
			'load' : luffy.common.Util.bind(this, function(oEvent) {
				var oResponse = oEvent.response;
				
				this._htRequestedUrl[sUrl] = "LOADED";
				// this.oApp.exec("TEMPLATE_RECEIVED", [sUrl, oResponse]); -- TEST 를 위한 코드
				
				this._parseTemplate(oResponse.text());
				this._runCallbackQueue();
				
			}),
			
			'complete' : luffy.common.Util.bind(this, function(oEvent) {
				this._nRemainedReq--;
				if (this._nRemainedReq === 0) {
					setTimeout(function() {
						oSelf.status = nhn.husky.PLUGIN_STATUS.READY;
					}, 0);
				}
			})
		}).request('GET', sUrl, {});
		
		this._htRequestedUrl[sUrl] = "LOADING";
		// this.oApp.exec("TEMPLATE_REQUESTED", [sUrl]); -- TEST 를 위한 코드
	},

	_runSingleCallback: function(oRequest, fCallback) {
		fCallback.call(this, this._processTemplate(oRequest), oRequest.id);
	},
	
	/**
	 * 템플릿을 파싱하여 데이터 및 서브템플릿과 바인딩한다. (데이터 및 서브템플릿이 있을 경우)
	 */
	_processTemplate: function(oRequest) {
		var sTemplate = this._htCache[oRequest.id];
		if (oRequest.subTemplates) {
			var htSubTemplateData = {};
			for (var sPlaceholderId in oRequest.subTemplates) {
				var sSubTemplate = this._processTemplate(oRequest.subTemplates[sPlaceholderId]);
				htSubTemplateData[sPlaceholderId] = sSubTemplate;
			} 
			sTemplate = luffy.common.Template.get(sTemplate).process(htSubTemplateData);
		}
		
		if (oRequest.data) {
			var oResult = luffy.common.Template.get(sTemplate).process(oRequest.data);
			return oResult;
		} else {
			return sTemplate;
		}
	}

});